package com.gzjyh.payment.spunifiedpay.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * 通用线程池配置
 * 可以使用@Async("selfAsyncExecutor")注解来使用
 */
@Slf4j
@Configuration
public class AsyncExecutorConfig {

    @Value("${executor.corePoolSize:0}")
    private int corePoolSize;
    @Value("${executor.maxPoolSize:0}")
    private int maxPoolSize;
    @Value("${executor.queueCapacity:0}")
    private int queueCapacity;
    @Value("${executor.keepAliveSeconds:0}")
    private int keepAliveSeconds;

    @Bean(name = "selfAsyncExecutor")
    public ThreadPoolTaskExecutor executor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        //核心线程数
        // 使用配置的值，如果配置没有提供，则采用默认逻辑
        int cpuNum = corePoolSize == 0 ? getCPUNum() : corePoolSize;
        log.info("selfAsyncExecutor Core pool size: " + cpuNum);

        taskExecutor.setCorePoolSize(cpuNum);
        //线程池维护线程的最大数量,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        taskExecutor.setMaxPoolSize(maxPoolSize == 0 ? cpuNum * 2 : maxPoolSize);
        //缓存队列
        taskExecutor.setQueueCapacity(queueCapacity == 0 ? 200 : queueCapacity);
        //许的空闲时间,当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
        taskExecutor.setKeepAliveSeconds(keepAliveSeconds == 0 ? 60 : keepAliveSeconds);
        //异步方法内部线程名称
        taskExecutor.setThreadNamePrefix("unifiedpay-async-");
        /**
         * 当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize，如果还有任务到来就会采取任务拒绝策略
         * 通常有以下四种策略：
         * ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
         * ThreadPoolExecutor.DiscardPolicy：也是丢弃任务，但是不抛出异常。
         * ThreadPoolExecutor.DiscardOldestPolicy：丢弃队列最前面的任务，然后重新尝试执行任务（重复此过程）
         * ThreadPoolExecutor.CallerRunsPolicy：重试添加当前的任务，自动重复调用 execute() 方法，直到成功
         */
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        taskExecutor.initialize();
        return taskExecutor;
    }

    // 获取当前机器的核数
    private int getCPUNum() {
        int i = Runtime.getRuntime().availableProcessors();
        return i == 0 ? 5 : i;
    }
}
